package top.hcode.hoj.shiro;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.*;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.nutz.lang.Lang;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.hcode.hoj.dao.org.OrgUserDao;
import top.hcode.hoj.dao.user.UserInfoEntityService;
import top.hcode.hoj.dao.user.UserRoleEntityService;
import top.hcode.hoj.mapper.RoleAuthMapper;
import top.hcode.hoj.pojo.entity.org.OrgUser;
import top.hcode.hoj.pojo.entity.user.Auth;
import top.hcode.hoj.pojo.entity.user.Role;
import top.hcode.hoj.pojo.entity.user.UserInfo;
import top.hcode.hoj.utils.JwtUtils;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author: Himit_ZH
 * @Date: 2020/7/19 22:57
 * @Description:
 */
@Slf4j
@Component
public class AccountRealm extends AuthorizingRealm {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private UserRoleEntityService userRoleEntityService;

    @Autowired
    private UserInfoEntityService userInfoEntityService;

    @Autowired
    private RoleAuthMapper roleAuthMapper;

    @Autowired
    private OrgUserDao orgUserDao;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    @Override
    protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
        Collection<String> roles = info.getRoles();
        if (roles == null || roles.isEmpty()) {
            return false;
        }

        return roles.contains("root") || roles.contains(roleIdentifier);
    }

    @Override
    protected void checkPermission(Permission permission, AuthorizationInfo info) {
        if (this.hasRole("root", info)) {
            return;
        }

        super.checkPermission(permission, info);
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        AccountProfile user = (AccountProfile) principals.getPrimaryPrincipal();
        //角色权限列表
        List<String> permissionsNameList = new LinkedList<>();
        //用户角色列表
        List<String> roleNameList = new LinkedList<>();

        String uid = user.getUid();
        if (BooleanUtil.isTrue(user.isOrgUser())) {
            // 学校用户
            OrgUser orgUser = orgUserDao.getById(uid);
            if (orgUser != null) {
                roleNameList.add(Lang.equals(1, orgUser.getUserType()) ? "teacher" : "student");
            }
        } else {
            //获取该用户角色所有的权限
            List<Role> roles = userRoleEntityService.getRolesByUid(uid);
            for (Role role : roles) {
                roleNameList.add(role.getRole());
                for (Auth auth : roleAuthMapper.getRoleAuths(role.getId()).getAuths()) {
                    permissionsNameList.add(auth.getPermission());
                }
            }
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 添加角色
        authorizationInfo.addRoles(roleNameList);
        //添加权限
        authorizationInfo.addStringPermissions(permissionsNameList);
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        JwtToken jwt = (JwtToken) token;

        String userId = jwtUtils.getClaimByToken((String) jwt.getPrincipal()).getSubject();
        boolean isOrgUser = StrUtil.isNumeric(userId) && userId.length() != 32 && userId.length() > 18;

        AccountProfile profile = new AccountProfile();
        profile.setUid(userId);

        if (isOrgUser) {
            // 学校用户
            OrgUser orgUser = orgUserDao.getById(userId);
            if (orgUser == null) {
                throw new UnknownAccountException("账户不存在");
            }
            if (!BooleanUtil.isTrue(orgUser.getEnabled())) {
                throw new LockedAccountException("该账户已被封禁，请联系管理员进行处理");
            }

            BeanUtil.copyProperties(orgUser, profile);
            profile.setOrgUser(true);
            profile.setUid(orgUser.getId());
            profile.setStatus(0);
        } else {
            // oj用户
            QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("uuid", userId)
                    .select("uuid", "username", "nickname", "realname", "title_name", "title_color", "avatar", "status");

            UserInfo userInfo = userInfoEntityService.getOne(queryWrapper, false);
            if (userInfo == null) {
                throw new UnknownAccountException("账户不存在！");
            }
            if (userInfo.getStatus() == 1) {
                throw new LockedAccountException("该账户已被封禁，请联系管理员进行处理！");
            }

            BeanUtil.copyProperties(userInfo, profile);
        }

        return new SimpleAuthenticationInfo(profile, jwt.getCredentials(), getName());
    }
}